package cn.tedu.mm.admin.section.config;

import cn.tedu.mm.admin.section.filter.JwtAuthorizationFilter;
import cn.tedu.mm.common.enumerator.ServiceCode;
import cn.tedu.mm.common.web.JsonResult;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;
import java.io.PrintWriter;


@Configuration
@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private JwtAuthorizationFilter jwtAuthorizationFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 允许跨域访问
        http.cors();

        // 调整Session创建策略，改为：不使用Session
        // SessionCreationPolicy.NEVER：从不主动创建Session，但是，如果Session已存在，则会使用它
        // SessionCreationPolicy.STATELESS：保持为“无状态”，具体表现为从不使用Session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // 将自定义的JWT过滤器添加到Security框架中特定的过滤器之前
        http.addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class);

        // 处理“在未通过认证的情况下，向需要通过认证的资源发起请求，导致403错误”的问题
        http.exceptionHandling().authenticationEntryPoint((request, response, e) -> {
            response.setContentType("application/json; charset=utf-8");
            String message = "操作失败，您当前未登录，或登录已过期！";
            JsonResult jsonResult = JsonResult.fail(
                    ServiceCode.ERROR_UNAUTHORIZED, message);
            String jsonString = JSON.toJSONString(jsonResult);
            PrintWriter writer = response.getWriter();
            writer.println(jsonString);
        });

        // 禁用“防止伪造的跨域攻击的防御机制”
        http.csrf().disable();

        // 白名单
        // 不在白名单中的请求，必须通过Security框架的认证机制，否则会响应403
        // Security框架的认证机制就是：检查SecurityContext中是否存在有效的Authentication
        String[] whiter = {
                "/doc.html",
                "/**/*.css",
                "/**/*.js",
                "/user/*",
                "/swagger-resources",
                "/v2/api-docs",
                "/admin/*"
        };

        // 请求授权
        http.authorizeRequests() // 开始配置请求授权
                .mvcMatchers(whiter) // 匹配某些请求
                .permitAll() // 许可，即不需要通过认证即可访问
                .anyRequest() // 匹配任何请求，实际表现为“除了以上配置过的以外的其它请求”
                .authenticated() // 需要已经通过认证
        ;

        // 根据是否调用formLogin()方法，表示是否启用登录页与登出页
        // 当尝试访问某个“需要已经通过认证”的资源，但当前却未通过认证
        // -- 如果启用了登录页，则会自动重定向到登录页
        // -- 如果未启用登录页，则响应403错误
         http.formLogin();
    }
}
